package org.zs.miracle.service.dict.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.zs.miracle.common.base.dto.BaseManyLongIdDTO;
import org.zs.miracle.common.exception.UserFriendlyException;
import org.zs.miracle.common.util.ModelMapperUtil;
import org.zs.miracle.common.util.tree.ITreeNode;
import org.zs.miracle.common.util.tree.TreeUtil;
import org.zs.miracle.entity.dict.DictDataEntity;
import org.zs.miracle.entity.dict.DictTypeEntity;
import org.zs.miracle.mapper.DictDataMapper;
import org.zs.miracle.mapper.DictTypeMapper;
import org.zs.miracle.service.dict.IDictService;
import org.zs.miracle.service.dict.model.dto.AddDictInputDTO;
import org.zs.miracle.service.dict.model.dto.AddDictTypeInputDTO;
import org.zs.miracle.service.dict.model.dto.EditDictDTO;
import org.zs.miracle.service.dict.model.dto.EditDictTypeDTO;
import org.zs.miracle.service.dict.model.dto.SetStateDictDTO;
import org.zs.miracle.service.dict.model.vo.DictDataVO;
import org.zs.miracle.service.dict.model.vo.DictTypeTreeVO;

@Service
@AllArgsConstructor
public class DictServiceImpl implements IDictService {
  
  DictDataMapper dictDataRepository;
  DictTypeMapper dictTypeRepository;
  
  @Override
  public Boolean addDictData(AddDictInputDTO inputDTO) {
    DictDataEntity dictionaryDataEntity = ModelMapperUtil.map(inputDTO, DictDataEntity.class);
    
    // 检查字典数据名称是否重复
    checkDictDataNameExistence(dictionaryDataEntity);
    // 检查字典数据编码是否重复
    checkDictDataCodeExistence(dictionaryDataEntity);
    
    this.dictDataRepository.insert(dictionaryDataEntity);
    return true;
  }
  
  @Override
  public Boolean delDictData(BaseManyLongIdDTO inputDTO) {
    // 根据id删除字典
    this.dictDataRepository.deleteByIds(inputDTO.getIds());
    return true;
  }
  
  @Override
  public Boolean setStateDictData(SetStateDictDTO inputDTO) {
    
    // 更新的数据
    DictDataEntity dictionaryDataEntity = new DictDataEntity();
    dictionaryDataEntity.setId(inputDTO.getId());
    dictionaryDataEntity.setEnable(inputDTO.getState());
    
    // 执行更新
    this.dictDataRepository.updateById(dictionaryDataEntity);
    return true;
  }
  
  @Override
  public Boolean editDictData(EditDictDTO inputDTO) {
    
    DictDataEntity dictDataEntityDB = this.dictDataRepository.selectById(inputDTO.getId());
    
    // 更新的数据
    DictDataEntity updateEntity =
        ModelMapperUtil.map(inputDTO, DictDataEntity.class);
    
    // 如果修改了字典数据名称，检查字典数据是否重复
    if (!StrUtil.equals(dictDataEntityDB.getName(), inputDTO.getName())) {
      checkDictDataNameExistence(updateEntity);
    }
    
    // 如果修改了字典数据编码，检查字典数据编码是否重复
    if (!StrUtil.equals(dictDataEntityDB.getCode(), inputDTO.getCode())) {
      checkDictDataCodeExistence(updateEntity);
    }
    
    // 执行更新
    this.dictDataRepository.updateById(updateEntity);
    
    return true;
  }
  
  @Override
  public List<DictDataVO> dictDataQueryList(Long dictTypeId) {
    return this.dictDataRepository.selectList(
        Wrappers.<DictDataEntity>lambdaQuery()
            .eq(DictDataEntity::getDictTypeId, dictTypeId)
            .orderByAsc(DictDataEntity::getSort), DictDataVO.class);
  }
  
  /**
   * 检查字典数据是否已存在
   *
   * @param dictData 字典数据
   */
  private void checkDictDataNameExistence(DictDataEntity dictData) {
    
    // 查询条件
    LambdaQueryWrapper<DictDataEntity> queryWrapper = Wrappers.<DictDataEntity>lambdaQuery()
        .eq(DictDataEntity::getDictTypeId, dictData.getDictTypeId());
    
    // 检查名称是否重复
    queryWrapper.eq(DictDataEntity::getName, dictData.getName());
    if (this.dictDataRepository.selectCount(queryWrapper) > 0) {
      throw new UserFriendlyException("该字典名称已存在", 451);
    }
  }
  
  private void checkDictDataCodeExistence(DictDataEntity dictData) {
    
    // 查询条件
    LambdaQueryWrapper<DictDataEntity> queryWrapper = Wrappers.<DictDataEntity>lambdaQuery()
        .eq(DictDataEntity::getDictTypeId, dictData.getDictTypeId());
    
    // 检查code是否重复
    queryWrapper.eq(DictDataEntity::getCode, dictData.getCode());
    if (this.dictDataRepository.selectCount(queryWrapper) > 0) {
      throw new UserFriendlyException("该字典编码已存在", 450);
    }
  }
  
  @Override
  public Boolean addDictType(AddDictTypeInputDTO inputDTO) {
    
    DictTypeEntity dictTypeEntity = ModelMapperUtil.map(inputDTO, DictTypeEntity.class);
    
    // 检查字典类型是否重复
    checkDictTypeExistence(dictTypeEntity);
    
    // 执行插入字典类型
    this.dictTypeRepository.insert(dictTypeEntity);
    return true;
  }
  
  @Override
  public Boolean delDictType(BaseManyLongIdDTO inputDTO) {
    // 根据id删除字典类型
    this.dictTypeRepository.deleteByIds(inputDTO.getIds());
    return true;
  }
  
  @Override
  public Boolean editDictType(EditDictTypeDTO inputDTO) {
    // 数据库中的数据
    DictTypeEntity dictTypeEntityDB = dictTypeRepository.selectById(inputDTO.getId());
    // 更新的数据
    DictTypeEntity updateEntity =
        ModelMapperUtil.map(inputDTO, DictTypeEntity.class);
    
    // 如果修改了类型名称
    if (!StrUtil.equals(dictTypeEntityDB.getName(), inputDTO.getName())) {
      // 检查字典类型是否重复
      this.checkDictTypeExistence(updateEntity);
    }
    
    // 执行更新
    this.dictTypeRepository.updateById(updateEntity);
    return true;
  }
  
  @Override
  public List<DictTypeTreeVO> dictTypeTree() {
    // 字典类型集合
    List<DictTypeTreeVO> dictTypeTreeVOS = this.dictTypeRepository.selectList(
        Wrappers.<DictTypeEntity>lambdaQuery()
            .orderByAsc(DictTypeEntity::getParentId, DictTypeEntity::getSort),
        DictTypeTreeVO.class);
    // 转换ITreeNode List
    List<ITreeNode<Long>> treeNodeList = new ArrayList<>(dictTypeTreeVOS.size());
    treeNodeList.addAll(dictTypeTreeVOS);
    // 转换树结构
    List<ITreeNode<Long>> tree = TreeUtil.listToTree(treeNodeList);
    // 转换DictTypeTreeVO List
    return ModelMapperUtil.mapList(tree, DictTypeTreeVO.class);
  }
  
  @Override
  public Boolean setStateDictType(SetStateDictDTO inputDTO) {
    // 更新的数据
    DictTypeEntity dictTypeEntity = new DictTypeEntity();
    dictTypeEntity.setId(inputDTO.getId());
    dictTypeEntity.setEnable(inputDTO.getState());
    
    // 执行更新
    this.dictTypeRepository.updateById(dictTypeEntity);
    return true;
  }
  
  /**
   * 检查字典类型是否已存在
   *
   * @param dictType 字典类型
   * @return true存在
   */
  private void checkDictTypeExistence(DictTypeEntity dictType) {
    // 查询条件
    LambdaQueryWrapper<DictTypeEntity> queryWrapper = Wrappers.<DictTypeEntity>lambdaQuery()
        .and(
            wrapper ->
                wrapper.eq(dictType.getParentId() != null, DictTypeEntity::getParentId,
                        dictType.getParentId())
                    .or()
                    .isNull(dictType.getParentId() == null, DictTypeEntity::getParentId)
        )
        .and(wrapper -> wrapper.eq(DictTypeEntity::getName, dictType.getName()));
    
    if (this.dictTypeRepository.selectCount(queryWrapper) > 0) {
      throw new UserFriendlyException("该字典类型已存在", 450);
    }
  }
}